{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 十分类问题示例\n",
    "- 输入层：784\n",
    "- 隐藏层1：200\n",
    "- 隐藏层2：200\n",
    "- 输出层：10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import  torch.nn as nn\n",
    "import  torch.nn.functional as F\n",
    "import  torch.optim as optim\n",
    "from    torchvision import datasets, transforms\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ../data\\MNIST\\raw\\train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100.0%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ../data\\MNIST\\raw\\train-images-idx3-ubyte.gz to ../data\\MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ../data\\MNIST\\raw\\train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "102.8%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ../data\\MNIST\\raw\\train-labels-idx1-ubyte.gz to ../data\\MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ../data\\MNIST\\raw\\t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100.0%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ../data\\MNIST\\raw\\t10k-images-idx3-ubyte.gz to ../data\\MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ../data\\MNIST\\raw\\t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "112.7%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ../data\\MNIST\\raw\\t10k-labels-idx1-ubyte.gz to ../data\\MNIST\\raw\n",
      "\n",
      "Train Epoch: 0 [0/60000 (0%)]\tLoss: 2.731099\n",
      "Train Epoch: 0 [20000/60000 (33%)]\tLoss: 0.900113\n",
      "Train Epoch: 0 [40000/60000 (67%)]\tLoss: 0.393657\n",
      "\n",
      "Test set: Average loss: 0.0017, Accuracy: 8982/10000 (90%)\n",
      "\n",
      "Train Epoch: 1 [0/60000 (0%)]\tLoss: 0.344151\n",
      "Train Epoch: 1 [20000/60000 (33%)]\tLoss: 0.323819\n",
      "Train Epoch: 1 [40000/60000 (67%)]\tLoss: 0.202595\n",
      "\n",
      "Test set: Average loss: 0.0013, Accuracy: 9194/10000 (92%)\n",
      "\n",
      "Train Epoch: 2 [0/60000 (0%)]\tLoss: 0.310733\n",
      "Train Epoch: 2 [20000/60000 (33%)]\tLoss: 0.185007\n",
      "Train Epoch: 2 [40000/60000 (67%)]\tLoss: 0.171467\n",
      "\n",
      "Test set: Average loss: 0.0012, Accuracy: 9295/10000 (93%)\n",
      "\n",
      "Train Epoch: 3 [0/60000 (0%)]\tLoss: 0.218163\n",
      "Train Epoch: 3 [20000/60000 (33%)]\tLoss: 0.157601\n",
      "Train Epoch: 3 [40000/60000 (67%)]\tLoss: 0.192392\n",
      "\n",
      "Test set: Average loss: 0.0011, Accuracy: 9349/10000 (93%)\n",
      "\n",
      "Train Epoch: 4 [0/60000 (0%)]\tLoss: 0.215715\n",
      "Train Epoch: 4 [20000/60000 (33%)]\tLoss: 0.206969\n",
      "Train Epoch: 4 [40000/60000 (67%)]\tLoss: 0.183960\n",
      "\n",
      "Test set: Average loss: 0.0010, Accuracy: 9412/10000 (94%)\n",
      "\n",
      "Train Epoch: 5 [0/60000 (0%)]\tLoss: 0.210940\n",
      "Train Epoch: 5 [20000/60000 (33%)]\tLoss: 0.221173\n",
      "Train Epoch: 5 [40000/60000 (67%)]\tLoss: 0.215062\n",
      "\n",
      "Test set: Average loss: 0.0009, Accuracy: 9455/10000 (95%)\n",
      "\n",
      "Train Epoch: 6 [0/60000 (0%)]\tLoss: 0.157422\n",
      "Train Epoch: 6 [20000/60000 (33%)]\tLoss: 0.165528\n",
      "Train Epoch: 6 [40000/60000 (67%)]\tLoss: 0.207410\n",
      "\n",
      "Test set: Average loss: 0.0008, Accuracy: 9498/10000 (95%)\n",
      "\n",
      "Train Epoch: 7 [0/60000 (0%)]\tLoss: 0.148253\n",
      "Train Epoch: 7 [20000/60000 (33%)]\tLoss: 0.121564\n",
      "Train Epoch: 7 [40000/60000 (67%)]\tLoss: 0.287132\n",
      "\n",
      "Test set: Average loss: 0.0008, Accuracy: 9515/10000 (95%)\n",
      "\n",
      "Train Epoch: 8 [0/60000 (0%)]\tLoss: 0.136370\n",
      "Train Epoch: 8 [20000/60000 (33%)]\tLoss: 0.096315\n",
      "Train Epoch: 8 [40000/60000 (67%)]\tLoss: 0.104491\n",
      "\n",
      "Test set: Average loss: 0.0008, Accuracy: 9547/10000 (95%)\n",
      "\n",
      "Train Epoch: 9 [0/60000 (0%)]\tLoss: 0.146980\n",
      "Train Epoch: 9 [20000/60000 (33%)]\tLoss: 0.131756\n",
      "Train Epoch: 9 [40000/60000 (67%)]\tLoss: 0.222444\n",
      "\n",
      "Test set: Average loss: 0.0007, Accuracy: 9574/10000 (96%)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "batch_size=200\n",
    "learning_rate=0.01\n",
    "epochs=10\n",
    "\n",
    "## 数据加载\n",
    "train_loader = torch.utils.data.DataLoader(\n",
    "    datasets.MNIST('../data', train=True, download=True,\n",
    "                   transform=transforms.Compose([\n",
    "                       transforms.ToTensor(),\n",
    "                       transforms.Normalize((0.1307,), (0.3081,))\n",
    "                   ])),\n",
    "    batch_size=batch_size, shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(\n",
    "    datasets.MNIST('../data', train=False, transform=transforms.Compose([\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize((0.1307,), (0.3081,))\n",
    "    ])),\n",
    "    batch_size=batch_size, shuffle=True)\n",
    "\n",
    "\n",
    "## 三个线性层\n",
    "w1, b1 = torch.randn(200, 784, requires_grad=True),\\\n",
    "         torch.zeros(200, requires_grad=True)\n",
    "w2, b2 = torch.randn(200, 200, requires_grad=True),\\\n",
    "         torch.zeros(200, requires_grad=True)\n",
    "w3, b3 = torch.randn(10, 200, requires_grad=True),\\\n",
    "         torch.zeros(10, requires_grad=True)\n",
    "\n",
    "## 初始化w\n",
    "torch.nn.init.kaiming_normal_(w1)\n",
    "torch.nn.init.kaiming_normal_(w2)\n",
    "torch.nn.init.kaiming_normal_(w3)\n",
    "\n",
    "\n",
    "def forward(x):\n",
    "    x = x@w1.t() + b1\n",
    "    x = F.relu(x)\n",
    "    x = x@w2.t() + b2\n",
    "    x = F.relu(x)\n",
    "    x = x@w3.t() + b3\n",
    "    x = F.relu(x)\n",
    "    return x\n",
    "\n",
    "\n",
    "\n",
    "optimizer = optim.SGD([w1, b1, w2, b2, w3, b3], lr=learning_rate)\n",
    "criteon = nn.CrossEntropyLoss()\n",
    "\n",
    "for epoch in range(epochs):\n",
    "\n",
    "    for batch_idx, (data, target) in enumerate(train_loader):\n",
    "        data = data.view(-1, 28*28)\n",
    "\n",
    "        logits = forward(data)\n",
    "        loss = criteon(logits, target)\n",
    "\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        # print(w1.grad.norm(), w2.grad.norm())\n",
    "        optimizer.step()\n",
    "\n",
    "        if batch_idx % 100 == 0:\n",
    "            print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n",
    "                epoch, batch_idx * len(data), len(train_loader.dataset),\n",
    "                       100. * batch_idx / len(train_loader), loss.item()))\n",
    "\n",
    "\n",
    "    test_loss = 0\n",
    "    correct = 0\n",
    "    for data, target in test_loader:\n",
    "        data = data.view(-1, 28 * 28)\n",
    "        logits = forward(data)\n",
    "        test_loss += criteon(logits, target).item()\n",
    "\n",
    "        pred = logits.data.max(1)[1]\n",
    "        correct += pred.eq(target.data).sum()\n",
    "\n",
    "    test_loss /= len(test_loader.dataset)\n",
    "    print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
    "        test_loss, correct, len(test_loader.dataset),\n",
    "        100. * correct / len(test_loader.dataset)))"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "4ce0e62306dd6a5716965d4519ada776f947e6dfc145b604b11307c10277ef29"
  },
  "kernelspec": {
   "display_name": "Python 3.9.6 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
